package data.join.com.socket;

import android.content.Context;
import android.text.TextUtils;

import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.DisconnectedBufferOptions;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttMessageListener;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.greenrobot.eventbus.EventBus;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import data.join.com.application.EventMessage;
import data.join.com.socket.util.SignUtil;
import data.join.com.utils.MyLog;
import data.join.com.utils.QuickShPref;
import data.join.com.utils.WakeLockUtils;

/**
 * Created by Administrator on 2017/10/18.
 */

public class AliMqttClient {
    private final String TAG = AliMqttClient.class.getSimpleName();

    private final static int CONNECT_LOCK_TIMEOUT = 20 * 1000;

    private static AliMqttClient mqttClient;

    //productKey：qhxnZOrnwQE， deviceName: 1234, deviceSecret：mWqWYbavQkIprgt9QFgC0Y6ESpAcJQqT

    /** 从控制台获取productKey、deviceName、deviceSecret信息*/
    private static String productKey = "qhxnZOrnwQE";
    private static String deviceName = "1234";
    private static String deviceSecret = "g6z7ILNi4lod8jpdD54OpcChaOM4IONW";
    /** 用于测试的topic */
    private static String subTopic = "/"+productKey+"/"+deviceName+"/get";
    private static String pubTopic = "/"+productKey+"/"+deviceName+"/pub";

    MqttAndroidClient mqttAndroidClient;

    String clientId = "ExampleAndroidClient";
    final String publishMessage = "Hello World!";

    Context mContext;

    MqttConnectOptions connOpts;

    private AliMqttClient(Context context){
        this.mContext = context;
        //clientId = ""+System.currentTimeMillis();
        createClient();
    }

    private void createClient(){
        String imei = QuickShPref.getInstance().getString(QuickShPref.DeviceImei);

        try {
            RegisterInfo registerInfo = QuickShPref.getInstance().getClass(imei,RegisterInfo.class);

            deviceSecret = registerInfo.data.mqtt_device_secret;
        }catch (Exception e){
            e.printStackTrace();
        }

        if(TextUtils.isEmpty(deviceSecret)){
            MyLog.E(TAG,"createClient deviceSecret is NULL");
            return;
        }

        deviceName = imei;

        subTopic = "/"+productKey+"/"+deviceName+"/get";

        MyLog.D(TAG,"createClient deviceName="+deviceName);

        //设备认证
        Map<String, String> params = new HashMap<String, String>();
        params.put("productKey", productKey); //这个是对应用户在控制台注册的 设备productkey
        params.put("deviceName", deviceName); //这个是对应用户在控制台注册的 设备name
        params.put("clientId", clientId);
        String t = System.currentTimeMillis()+"";
        params.put("timestamp", t);
        //mqtt服务器 ，tls的话ssl开头，tcp的话改成tcp开头
        String targetServer = "ssl://"+productKey+".iot-as-mqtt.cn-shanghai.aliyuncs.com:1883";
        //String targetServer = "ssl://139.196.135.135:1883";

        //客户端ID格式:
        String mqttclientId = clientId + "|securemode=2,signmethod=hmacsha1,timestamp="+t+"|"; //设备端自定义的标记，字符范围[0-9][a-z][A-Z]
        String mqttUsername = deviceName+"&"+productKey;//mqtt用户名格式
        String mqttPassword = SignUtil.sign(params, deviceSecret, "hmacsha1");//签名

        mqttAndroidClient = new MqttAndroidClient(mContext,targetServer, mqttclientId);

        connOpts = new MqttConnectOptions();
        connOpts.setMqttVersion(4);// MQTT 3.1.1
        connOpts.setAutomaticReconnect(true);
        connOpts.setKeepAliveInterval(300);
        connOpts.setUserName(mqttUsername);
        connOpts.setPassword(mqttPassword.toCharArray());
    }

    public static synchronized AliMqttClient getInstance(Context context){
        if(mqttClient == null){
            mqttClient = new AliMqttClient(context);
        }
        return mqttClient;
    }

    public void connectServer(){

        if(mqttAndroidClient == null){
            MyLog.D(TAG,"Error to connectServer: mqttAndroidClient is NULL");
            return;
        }

        mqttAndroidClient.setCallback(new MqttCallbackExtended() {
            @Override
            public void connectComplete(boolean reconnect, String serverURI) {

                if (reconnect) {
                    MyLog.D(TAG,"Reconnected to : " + serverURI);
                    // Because Clean Session is true, we need to re-subscribe
                    subscribeToTopic();
                } else {
                    MyLog.D(TAG,"Connected to: " + serverURI);
                }

                OfflineAlarmConnect.getInstance(mContext).stop();
            }

            @Override
            public void connectionLost(Throwable cause) {
                MyLog.D(TAG,"The Connection was lost.");

                WakeLockUtils.getDefault(mContext).acquireWakeLock(TAG,CONNECT_LOCK_TIMEOUT);
                OfflineAlarmConnect.getInstance(mContext).start();

                if(cause != null) cause.printStackTrace();
            }

            @Override
            public void messageArrived(String topic, MqttMessage message) throws Exception {
                String stringMsg = new String(message.getPayload());

                MyLog.D(TAG,"Incoming message: " + stringMsg);

                if(subTopic.equals(topic)){
                    EventBus.getDefault().post(new EventMessage(EventMessage.NEW_MQTT_COMMAND,stringMsg,null));
                }else{
                    MyLog.E(TAG,"unknow topic msg:"+topic);
                }
            }
            @Override
            public void deliveryComplete(IMqttDeliveryToken token) {}
        });


        try {
            WakeLockUtils.getDefault(mContext).acquireWakeLock(TAG,CONNECT_LOCK_TIMEOUT);

            mqttAndroidClient.connect(connOpts, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    DisconnectedBufferOptions disconnectedBufferOptions = new DisconnectedBufferOptions();
                    disconnectedBufferOptions.setBufferEnabled(true);
                    disconnectedBufferOptions.setPersistBuffer(true);
                    disconnectedBufferOptions.setDeleteOldestMessages(true);
                    mqttAndroidClient.setBufferOpts(disconnectedBufferOptions);
                    subscribeToTopic();
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    String error = "unknow error";
                    if(exception!= null)
                        error = exception.getMessage();
                    MyLog.D(TAG,"Failed to connect to Aliyun mqtt error:"+error);

                    WakeLockUtils.getDefault(mContext).releaseWakeLock(TAG);
                }
            });
        } catch (MqttException ex){
            ex.printStackTrace();
        }
    }


    public void subscribeToTopic(){
        try {
            mqttAndroidClient.subscribe(subTopic, 1, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    MyLog.D(TAG,"Success to subscribed :"+subTopic);
                    EventBus.getDefault().post(new EventMessage(EventMessage.MQTT_SUB_SUCCESS));
                    WakeLockUtils.getDefault(mContext).releaseWakeLock(TAG);
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    MyLog.D(TAG,"Failed to subscribe!");
                }

            });
        } catch (MqttException ex){
            System.err.println("Exception whilst subscribing");
            ex.printStackTrace();
        }
    }

    public boolean isConnected(){
        boolean ret = false;

        if(mqttAndroidClient != null){
            ret = mqttAndroidClient.isConnected();
        }

        return ret;
    }

    public void publishMessage(){

        try {
            MqttMessage message = new MqttMessage();
            message.setPayload(publishMessage.getBytes());
            //mqttAndroidClient.publish(publishTopic, message);
            mqttAndroidClient.publish(pubTopic, message, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    MyLog.D(TAG,"Message Published onSuccess:"+publishMessage);
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    MyLog.D(TAG,"Message Published onFailure:"+publishMessage);
                }
            });

            if(!mqttAndroidClient.isConnected()){
                MyLog.D(TAG,mqttAndroidClient.getBufferedMessageCount() + " messages in buffer.");
            }

        } catch (MqttException e) {
            System.err.println("Error Publishing: " + e.getMessage());
            e.printStackTrace();
        }
    }

}
